﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestSim
{
    public class Item
    {
        public string Name { get; set; }
    }

    public class Food : Item
    {
        public int Energy { get; set; }

        #region constructors

        public Food()
        {
        }

        public Food(string name, int energy)
        {
            this.Name = name;
            this.Energy = energy;
        }

        #endregion constructors
    }

    public interface InventoryItem
    {
        string Name { get; set; }

        int Quantity { get; set; }

        int CostPrice { get; set; }

        int SellingPrice { get; set; }
    }

    public class FoodInventoryItem : Food, InventoryItem
    {
        public int Quantity { get; set; }

        public int CostPrice { get; set; }

        public int SellingPrice { get; set; }

        public FoodInventoryItem()
        {
        }
    }

    public class Store
    {
        public string Name { get; set; }

        public List<InventoryItem> Inventory { get; set; }

        public Store()
        {
            this.Inventory = new List<InventoryItem>();

            #region food definition
            FoodInventoryItem bigBun = new FoodInventoryItem
            {
                Name = "Big Bun",
                Energy = 60,
                CostPrice = 50,
                SellingPrice = 60,
                Quantity = 3
            };
            FoodInventoryItem apple = new FoodInventoryItem
            {
                Name = "Apple",
                Energy = 20,
                CostPrice = 10,
                SellingPrice = 14,
                Quantity = 10
            };
            FoodInventoryItem dogFood = new FoodInventoryItem
            {
                Name = "Dog Food",
                Energy = 15,
                CostPrice = 3,
                SellingPrice = 5,
                Quantity = 20
            };
            #endregion food definition

            this.Inventory.Add(bigBun);
            this.Inventory.Add(apple);
            this.Inventory.Add(dogFood);
        }

        public Store(string name)
            : this()
        {
            this.Name = name;
        }


    }

    public class Player
    {
        public event EventHandler EnergyLow;
        public event EventHandler Expired;

        private System.ComponentModel.BackgroundWorker upkeep;

        public string Name { get; set; }

        private int MaxEnergy { get; set; }
        private int _Energy;
        public int Energy
        {
            get
            {
                return this._Energy;
            }
            set
            {
                this._Energy = value;
                if (this._Energy <= 0)
                {
                    if (this.Expired != null)
                    {
                        this.Expired(this, null);
                    }
                }
            }
        }

        public int Credit { get; set; }

        public int Metabolism { get; set; }

        public List<Food> FoodList { get; set; }

        #region constructors

        public Player(string name)
            : this(name, 100, 1000)
        {
        }

        public Player(string name, int energy, int metabolism)
        {
            this.Name = name;
            this.Energy = energy;
            this.MaxEnergy = 100;
            this.Credit = 100;
            this.Metabolism = metabolism;

            this.FoodList = new List<Food>();
            this.FoodList.Add(new Food("Big Bun", 60));
            this.FoodList.Add(new Food("Dog Food", 10));

            this.EnergyLow += Player_EnergyLow;
            this.Expired += Player_Expired;

            this.upkeep = new System.ComponentModel.BackgroundWorker();
            this.upkeep.DoWork += upkeep_DoWork;
            this.upkeep.RunWorkerAsync();
        }

        #endregion constructors

        public void FindFoodToBuy()
        {
            // TODO: stub; this is where we write code to probe store for available and affordable food.

        }

        public void FindFoodToEat()
        {
            Food foundFood = this.FoodList.Where(f => f.Energy > 0).OrderByDescending(f => f.Energy).FirstOrDefault();

            if (foundFood != null)
            {
                this.Eat(foundFood);
                this.FoodList.Remove(foundFood);
            }
            else
            {
                Console.WriteLine("{0} has no more food. :'(", this.Name);
            }

        }

        public void Eat(Food f)
        {
            this.EnergyLow += Player_EnergyLow;

            this.Energy = this.Energy + f.Energy;
            Console.WriteLine("{0} ate {1}(energy {2}).", this.Name, f.Name, f.Energy);

            if (this.Energy > (.6 * this.MaxEnergy))
            {
                Console.WriteLine("{0} has satisfied hunger (energy {1}).", this.Name, this.Energy);
            }
        }

        #region events

        void Player_EnergyLow(object sender, EventArgs e)
        {
            this.EnergyLow -= Player_EnergyLow;

            Player p = sender as Player;
            if (p != null)
            {
                Console.WriteLine("{0}'s energy level is low ({1}). Need to look for food.", p.Name, p.Energy);
                FindFoodToEat();
            }
            else
            {
                Console.WriteLine("Player_EnergyLow");
            }

        }

        void Player_Expired(object sender, EventArgs e)
        {
            this.Expired -= Player_Expired;

            Player p = sender as Player;
            if (p != null)
            {
                Console.WriteLine("{0} has expired.", p.Name);
            }
            else
            {
                Console.WriteLine("Player_Expired.");
            }
        }

        #endregion events

        void upkeep_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            while (this.Energy > 0)
            {
                System.Threading.Thread.Sleep(this.Metabolism);
                this.Energy = this.Energy - 1;

                //Console.WriteLine("{0} has {1} energy left.", this.Name, this.Energy);
                if (this.Energy < (.2 * this.MaxEnergy))
                {
                    if (this.EnergyLow != null)
                        this.EnergyLow(this, null);
                }
            }
        }
    }
}
